package com.kly.user.serviceImpl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.common.api.Response;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.common.utils.StringUtils;
import com.fqgj.common.utils.TimeUtils;
import com.fqgj.log.factory.LogFactory;
import com.fqgj.log.interfaces.Log;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.eventbus.AsyncEventBus;
import com.kly.enums.ParameterTypeEnum;
import com.kly.user.chatterService.UserLevelHelper;
import com.kly.user.constant.ConstantType;
import com.kly.user.constant.RedisKey;
import com.kly.user.db.dao.*;
import com.kly.user.db.dbo.FilterOnlineUserCustomerDBO;
import com.kly.user.db.dbo.UserConversationDBO;
import com.kly.user.db.dbo.UserTagDBO;
import com.kly.user.db.entity.*;
import com.kly.user.dto.*;
import com.kly.user.enums.*;
import com.kly.user.eventbus.ActionEnum;
import com.kly.user.eventbus.Event;
import com.kly.user.mapper.UserMapper;
import com.kly.user.service.UserService;
import com.kly.user.serviceImpl.traffic.forceConnect.FcTrafficHandler;
import com.kly.user.utils.ImagePrefixUtils;
import com.kly.user.utils.OtherSnowflake;
import com.kly.user.utils.ServiceUtils;
import com.kly.user.utils.UserSnowflake;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service("userService")
public class UserServiceImpl implements UserService {

    private static Log logger = LogFactory.getLog(UserServiceImpl.class);

    @Resource
    UserMapper userMapper;
    @Resource
    UserDao userDao;
    @Resource
    UserAccountsDao userAccountsDao;
    @Resource
    UserAlbumsDao userAlbumsDao;
    @Resource
    UserAlbumsContentDao userAlbumsContentDao;
    @Resource
    UserInterestsDao userInterestsDao;
    @Resource
    UserProfileDao userProfileDao;
    @Resource
    InterestDao interestDao;
    @Resource
    UserTurnOnsDao userTurnOnsDao;
    @Resource
    UserBehaviorGpsDao userBehaviorGpsDao;
    @Resource
    UserBehaviorWifiDao userBehaviorWifiDao;
    @Resource
    UserGreetingContentDao userGreetingContentDao;
    @Resource
    UserChatOnlineRecordDao chatOnlineRecordDao;
    @Resource
    private UserChatterMappingDao userChatterMappingDao;
    @Resource
    UserMsgDao userMsgDao;
    @Resource
    RedisClient redisClient;
    @Resource
    private UserAccessRongcloudDao userAccessRongcloudDao;
    @Resource
    UserWlmDao userWlmDao;
    @Resource
    private UserOnlineLogDao userOnlineLogDao;
    @Resource
    UserMsgSendTotalDao userMsgSendTotalDao;
    @Resource
    UserTagDao userTagDao;
    @NacosValue(value = "${default.user.chat.level:[{\"levelName\":\"0\",\"sortBy\":1,\"value\":0},{\"levelName\":\"1\",\"sortBy\":2,\"value\":5},{\"levelName\":\"2\",\"sortBy\":3,\"value\":15},{\"levelName\":\"3\",\"sortBy\":4,\"value\":30},{\"levelName\":\"4\",\"sortBy\":5,\"value\":60},{\"levelName\":\"5\",\"sortBy\":6,\"value\":100},{\"levelName\":\"6\",\"sortBy\":7,\"value\":150},{\"levelName\":\"7\",\"sortBy\":8,\"value\":220},{\"levelName\":\"8\",\"sortBy\":9,\"value\":300},{\"levelName\":\"9\",\"sortBy\":10,\"value\":400},{\"levelName\":\"10\",\"sortBy\":11,\"value\":999999}]}", autoRefreshed = true)
    private String defaultUserChatLevelConfig;
    @Resource
    UserLogoutDao userLogoutDao;
    @Resource
    SystemDictDao systemDictDao;

    @Resource
    IssueUsersDao issueUsersDao;
    @Resource
    UserOnlineDailyLogDao userOnlineDailyLogDao;
    @Resource
    UserConversationChatterDao userConversationChatterDao;

    @NacosValue(value = "${push.to.meboo.switch:false}", autoRefreshed = true)
    private boolean enablePushToMebooSwitch;

    @NacosValue(value = "${chat.conversation.flag:1}", autoRefreshed = true)
    private Integer chatConversationFlag;
    /**
     * 用户GSP地理位置已授权
     */
    private static final Integer HAS_GRANT_PRIVILEGE = 1;
    private static final Integer ONE = 1;
    private static final Integer TWO = 2;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response<UserInfoDto> changeUserInfo(UserChangeDto userChange, String userCode) {

        logger.info("=====addUserTag, userCode:{}, userChange:{}", userChange, JSONObject.toJSONString(userChange));

        if (userChange.getBirthday() != null) {
            int age = DateUtil.ageOfNow(DateUtil.offsetDay(userChange.getBirthday(), -2));
            if (age < 18) {
                return Response.error(ResultStatus.ILLEGAL_AGE);
            }
        }
        UserEntity userEntity = userDao.selectByUserCode(userCode);
        if (userEntity == null) {
            return Response.error(ResultStatus.USER_NOT_EXIST);
        }
        String extendInfo = userEntity.getExtendInfo();
        UserEntity user = userMapper.UserChangeToUser(userChange);
        //重新设置extendInfo
        user.setExtendInfo(extendInfo);
        //用户只有在初始化后，完善信息时允许修改gender值
        user.setGender(null);
        user.setLookingFor(userChange.getLookingFor());
        user.setUserCode(userCode);
        //返回值UserInfoDto必要参数
        user.setStatus(UserStatus.ACTIVE.getType());
        if (Objects.isNull(user.getRegisterDate())) {
            user.setRegisterDate(userEntity.getGmtCreate());
            //注册完用户添加到新增
            if (userEntity.getStatus() != 2) {
                long delayedTime = System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(10, TimeUnit.SECONDS);
                redisClient.zAdd(RedisKey.NEW_USER_LIST, delayedTime, userEntity.getUserCode());

                delayedTime = System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(1800, TimeUnit.SECONDS);
                redisClient.zAdd(RedisKey.THIRTY_LATER_USER_LIST, delayedTime, userEntity.getUserCode());
            }
        }

        //修改UserInterests,当兴趣大于八条不做插入
        if (userChange.getInterests() != null && !userChange.getInterests().isEmpty() && userChange.getInterests().size() < 9) {
            //对兴趣做去重处理
            List<String> stringinterestList = userChange.getInterests().stream().distinct().collect(Collectors.toList());
            List<UserInterestsEntity> interestsList = new ArrayList<>();
            //查询表中兴趣
            Map<String, InterestEntity> map = listToMap(interestDao.selectByParams(new HashMap<>()));
            for (String str : stringinterestList) {
                if (map.get(str) != null) {
                    UserInterestsEntity userInterest = new UserInterestsEntity();
                    userInterest.setUserCode(userCode);
                    userInterest.setInterestCode(str);
                    userInterest.setInterest(map.get(str).getInterestName());
                    interestsList.add(userInterest);
                }
            }
            if (interestsList.size() > 0) {
                userInterestsDao.deleteByUserCode(userCode);
                userInterestsDao.batchInsert(interestsList);
            }
        }

        // IOS包如果未填写兴趣，需要删除全部兴趣标签
        if (StringUtils.isNotEmpty(userEntity.getAppCode())) {
            if (userEntity.getAppCode().equals("sparksy_ios")) {
                if (CollectionUtils.isEmpty(userChange.getInterests())) {
                    userInterestsDao.deleteByUserCode(userCode);
                }
            }
        }

        //修改UserAlbums和UserAlbumsContent
        if (userChange.getImages() != null && !userChange.getImages().isEmpty()) {
            userChange.setAvatarUrl(userChange.getImages().get(0));
            Map<String, Object> params = ServiceUtils.getParams();
            params.put("userCode", userCode);
            params.put("type", ConstantType.PUBLIC_PHOTO);
            List<UserAlbumsEntity> userAlbumsEntities = userAlbumsDao.selectByParams(params);
            //如果存在公开相册则修改相册内容
            if (userAlbumsEntities != null && !userAlbumsEntities.isEmpty()) {
                saveAlbumsContent(userChange, userAlbumsEntities.get(0));
            } else {
                UserAlbumsEntity userAlbumsEntity = new UserAlbumsEntity();
                userAlbumsEntity.setUserCode(userCode);
                userAlbumsEntity.setAlbumCode(String.valueOf(OtherSnowflake.getInstance().nextId()));
                userAlbumsEntity.setStatus(ConstantType.ALBUM_STATUS);
                userAlbumsEntity.setType(ConstantType.PUBLIC_PHOTO);
                userAlbumsDao.insert(userAlbumsEntity);
                saveAlbumsContent(userChange, userAlbumsEntity);
            }
        }

        // 修改I want / You accept / body shape
        addUserTag(userChange, userCode);

        Map<Integer, String> updates = new HashMap<>();
        if (StringUtils.isNotEmpty(userChange.getAboutMe())) {
            updates.put(ONE, userChange.getAboutMe());
        } else {
            if (userEntity.getAppCode().equals("sparksy_ios")) {
                updates.put(ONE, "");
            }
        }
        if (StringUtils.isNotEmpty(userChange.getSocialConnections())) {
            updates.put(TWO, userChange.getSocialConnections());
        }

        if (!updates.isEmpty()) {
            Map<String, Object> params = ServiceUtils.getParams();
            params.put("userCode", userCode);
            List<UserProfileEntity> userProfiles = userProfileDao.selectByParams(params);

            // Convert list to map for O(1) access
            Map<Integer, UserProfileEntity> userProfileMap = userProfiles.stream().collect(Collectors.toMap(UserProfileEntity::getUserProfileType, Function.identity()));

            for (Map.Entry<Integer, String> entry : updates.entrySet()) {
                UserProfileEntity userProfile = userProfileMap.get(entry.getKey());
                if (userProfile == null) {
                    userProfile = new UserProfileEntity();
                    userProfile.setUserCode(userCode);
                    userProfile.setUserProfileType(entry.getKey());
                    userProfile.setAboutMe(entry.getValue());
                    userProfileDao.insert(userProfile);
                } else {
                    userProfile.setAboutMe(entry.getValue());
                    userProfileDao.updateByPrimaryKey(userProfile);
                }
            }
        }


        if (isUserDataComplete(userChange, userEntity)) {
            // 用户只有在初始化后，完善信息时允许修改gender值,和状态值
            user.setStatus(UserStatus.ACTIVE.getType());
            user.setGender(userChange.getGender());
        }

        if (UserStatus.ACTIVE.getType() == user.getStatus() && user.getRegisterDate() == null) {
            user.setRegisterDate(new Date());
        }

        //设置扩展信息
        builderExtendInfo(userChange, user);
        userDao.update(user);


        UserInfoDto userInfoDto = userMapper.UserDtoToUserInfo(user);
        userInfoDto.setAvatarUrl(getImageUrl(userInfoDto.getAvatarUrl()));
        userInfoDto.setAboutMe(userChange.getAboutMe());
        userInfoDto.setImages(userChange.getImages());
        userInfoDto.setImagesV2(userChange.getImagesV2());
        userInfoDto.setInterests(userChange.getInterests());
        userInfoDto.setSocialConnections(userChange.getSocialConnections());


        return Response.ok(userInfoDto);
    }

    private void addUserTag(UserChangeDto userChange, String userCode) {
        if (Objects.nonNull(userChange.getIWant())) {
            userTagDao.add(userCode, ConstantType.I_WANT, userChange.getIWant());
        }
        userTagDao.batchAdd(userCode, ConstantType.YOU_ACCEPT, userChange.getYouAccept());
        userTagDao.batchAdd(userCode, ConstantType.BODY_SHAPE, userChange.getBodyShape());
    }


    @Override
    public Response editModelInfo(ModelInfoChangeDto chatterInfoChangeDto) {

        UserEntity userEntity = userDao.selectByUserCode(chatterInfoChangeDto.getUserCode());
        if (userEntity == null) {
            return Response.error(ResultStatus.USER_NOT_EXIST);
        }

        if (chatterInfoChangeDto.getInterests() != null && chatterInfoChangeDto.getInterests().size() <= 8) {
            //对兴趣做去重处理
            List<String> stringinterestList = chatterInfoChangeDto.getInterests().stream().distinct().collect(Collectors.toList());
            List<UserInterestsEntity> interestsList = new ArrayList<>();
            //查询表中兴趣
            Map<String, InterestEntity> map = listToMap(interestDao.selectByParams(new HashMap<>()));
            for (String str : stringinterestList) {
                if (map.get(str) != null) {
                    UserInterestsEntity userInterest = new UserInterestsEntity();
                    userInterest.setUserCode(chatterInfoChangeDto.getUserCode().toString());
                    userInterest.setInterestCode(str);
                    userInterest.setInterest(map.get(str).getInterestName());
                    interestsList.add(userInterest);
                }
            }
            userInterestsDao.deleteByUserCode(chatterInfoChangeDto.getUserCode().toString());
            if (interestsList.size() > 0) {
                userInterestsDao.batchInsert(interestsList);
            }
        }

        // 修改扩展信息  身高 turn0nes
        if (chatterInfoChangeDto.getHeight() != null) {
            if (StringUtils.isNotEmpty(userEntity.getExtendInfo())) {
                ExtendInfoDto extendInfoDto = JSONUtil.toBean(userEntity.getExtendInfo(), ExtendInfoDto.class);
                if (chatterInfoChangeDto.getHeight() != null) {
                    extendInfoDto.setHeight(chatterInfoChangeDto.getHeight());
                }
                userEntity.setExtendInfo(JSONUtil.toJsonStr(extendInfoDto));
            } else {
                ExtendInfoDto extendInfo = new ExtendInfoDto();
                extendInfo.setHeight(chatterInfoChangeDto.getHeight());
                userEntity.setExtendInfo(JSONUtil.toJsonStr(extendInfo));
            }
            userDao.update(userEntity);
        }

        // 修改turn0nes
        if (chatterInfoChangeDto.getTurnOns() != null) {
            if (StringUtils.isNotEmpty(userEntity.getExtendInfo())) {
                ExtendInfoDto extendInfoDto = JSONUtil.toBean(userEntity.getExtendInfo(), ExtendInfoDto.class);
                if (chatterInfoChangeDto.getTurnOns() != null) {
                    extendInfoDto.setTurnOnsList(chatterInfoChangeDto.getTurnOns());
                }
                userEntity.setExtendInfo(JSONUtil.toJsonStr(extendInfoDto));
            } else {
                ExtendInfoDto extendInfo = new ExtendInfoDto();
                extendInfo.setTurnOnsList(chatterInfoChangeDto.getTurnOns());
                userEntity.setExtendInfo(JSONUtil.toJsonStr(extendInfo));
            }
            userDao.update(userEntity);
        }

        if (chatterInfoChangeDto.getWAYH() != null) {
            Map<String, Object> params = ServiceUtils.getParams();
            params.put("userCode", chatterInfoChangeDto.getUserCode());
            List<UserProfileEntity> userProfiles = userProfileDao.selectByParams(params);

            // Convert list to map for O(1) access
            Map<Integer, UserProfileEntity> userProfileMap = userProfiles.stream().collect(Collectors.toMap(UserProfileEntity::getUserProfileType, Function.identity()));
            UserProfileEntity userProfile = userProfileMap.get(TWO);
            if (userProfile == null) {
                userProfile = new UserProfileEntity();
                userProfile.setUserCode(chatterInfoChangeDto.getUserCode().toString());
                userProfile.setUserProfileType(TWO);
                userProfile.setAboutMe(chatterInfoChangeDto.getWAYH());
                userProfileDao.insert(userProfile);
            } else {
                userProfile.setAboutMe(chatterInfoChangeDto.getWAYH());
                userProfileDao.updateByPrimaryKey(userProfile);
            }

        }

        return Response.ok();

    }

    /**
     * 用户修改扩展信息
     *
     * @param userChange 用户修改信息
     * @param user       用户当前信息
     */
    public void builderExtendInfo(UserChangeDto userChange, UserEntity user) {
        if (userChange.getHeight() != null || userChange.isHideHeight() || userChange.getTurnOnsList() != null || userChange.getConstellation() != null) {
            if (StringUtils.isNotEmpty(user.getExtendInfo())) {
                ExtendInfoDto extendInfoDto = JSONUtil.toBean(user.getExtendInfo(), ExtendInfoDto.class);
                BeanUtil.copyProperties(userChange, extendInfoDto, CopyOptions.create().setIgnoreNullValue(true));
                user.setExtendInfo(JSONUtil.toJsonStr(extendInfoDto));
            } else {
                ExtendInfoDto extendInfo = new ExtendInfoDto();
                BeanUtil.copyProperties(userChange, extendInfo, CopyOptions.create().setIgnoreNullValue(true));
                user.setExtendInfo(JSONUtil.toJsonStr(extendInfo));
            }
        }
    }


    Map<String, InterestEntity> listToMap(List<InterestEntity> list) {
        Map<String, InterestEntity> map = new HashMap<>();
        for (InterestEntity interestEntity : list) {
            map.put(String.valueOf(interestEntity.getId()), interestEntity);
        }
        return map;
    }


    /**
     * 验证用户完整性
     *
     * @param userChange 用户添加或修改信息
     * @param userEntity user表中数据
     * @return 是否允许修改
     */
    private static boolean isUserDataComplete(UserChangeDto userChange, UserEntity userEntity) {
        return StringUtils.isNotEmpty(userChange.getNickName()) && userChange.getLookingFor() != null && StringUtils.isNotEmpty(userChange.getAvatarUrl()) && userChange.getBirthday() != null && userChange.getGender() != null;
    }


    /**
     * 当方法为非public时会导致事务失效，所以改为public修饰，此方法不对外暴露
     *
     * @param userChange 用户修改内容
     * @param UserAlbums 用户相册信息
     */
    public void saveAlbumsContent(UserChangeDto userChange, UserAlbumsEntity UserAlbums) {
        List<UserAlbumsContentEntity> albumsContents = new ArrayList<>();
        List<String> images = Lists.newArrayList();
        List<ImagesDto> imagesV2 = Lists.newArrayList();

        for (String image : userChange.getImages()) {
            final String imageCode = String.valueOf(OtherSnowflake.getInstance().nextId());
            UserAlbumsContentEntity userAlbumsContent = new UserAlbumsContentEntity();
            userAlbumsContent.setAlbumCode(UserAlbums.getAlbumCode());
            userAlbumsContent.setStatus(ConstantType.ALBUM_STATUS);
            images.add(getImageUrl(image));
            imagesV2.add(ImagesDto.builder().imageCode(imageCode).imageUrl(getImageUrl(image)).build());
            userAlbumsContent.setImageUrl(image);
            userAlbumsContent.setImageCode(imageCode);
            userAlbumsContent.setType(ImageType.IMAGE.getType());
            userAlbumsContent.setAlbumType(AlbumsType.PERSONAL_ALBUMS.getType());
            albumsContents.add(userAlbumsContent);
        }
        //删除原相册内容
        userAlbumsContentDao.deleteByAlbumCode(UserAlbums.getAlbumCode());
        //执行更新操作
        userAlbumsContentDao.batchInsert(albumsContents);
        userChange.setImages(images);
        userChange.setImagesV2(imagesV2);
    }

    /**
     * 查询所有有效的注册用户
     *
     * @return
     */
    @Override
    public Response<UserCodeDto> selectActiveUser(String userCode) {
        final UserEntity user = userDao.selectActiveUser(userCode);
        if (Objects.isNull(user)) {
            return Response.ok();
        }
        return Response.ok(userMapper.toUserCodeDto(user));

    }

    @Override
    public Response<UserInfoDto> getUserByUserCode(String userCode) {
        Map<String, Object> param = ServiceUtils.getParams();
        param.put("userCode", userCode);
        UserEntity userEntity = userDao.selectByUserCode(userCode);
        if (userEntity == null) {
            return Response.error(ResultStatus.USER_NOT_EXIST);
        }
        UserInfoDto userInfoDto = userMapper.UserDtoToUserInfo(userEntity);
        if (userEntity.getGpsPrivilege() == 1) {
            UserBehaviorGpsEntity userBehaviorGpsEntity = userBehaviorGpsDao.getLastGps(userEntity.getUserCode());
            if (userBehaviorGpsEntity != null) {
                userInfoDto.setLat(userBehaviorGpsEntity.getLat());
                userInfoDto.setLng(userBehaviorGpsEntity.getLng());
                userInfoDto.setState(userBehaviorGpsEntity.getStateAbbr());
                userInfoDto.setCity(userBehaviorGpsEntity.getCity());
            }
        }
        userInfoDto.setUserValid(userEntity.getStatus().equals(UserStatus.ACTIVE.getType()));
        List<UserAlbumsContentEntity> contentEntities = userAlbumsContentDao.selectByUserCode(userCode, ConstantType.PUBLIC_PHOTO);

        List<UserAlbumsContentEntity> picturesNumber = userAlbumsContentDao.selectByUserCode(userCode, ConstantType.PRIVATE_ALBUM);
        if (CollUtil.isNotEmpty(picturesNumber)) {
            userInfoDto.setPrivateAlbums(picturesNumber.size());
        }
        String avatarUrl = userInfoDto.getAvatarUrl();
        userInfoDto.setAvatarUrl(getImageUrl(avatarUrl));
        if (contentEntities != null && !contentEntities.isEmpty()) {

//            List<String> imageUrlList = contentEntities.stream().map(p -> {
//                int defaultFlag = 0;
//                if (Objects.equals(userInfoDto.getAvatarUrl(), p.getImageUrl())) {
//                    defaultFlag = 1;
//                }
//                return ImagesDto.builder().imageCode(p.getImageCode()).imageUrl(getImageUrl(p.getImageUrl())).defaultFlag(defaultFlag).build();
//            }).sorted(Comparator.comparingInt(ImagesDto::getDefaultFlag).reversed()).map(entity -> getImageUrl(entity.getImageUrl()))
//                    .collect(Collectors.toList());
            List<String> imageUrlList = Lists.newArrayList();
            List<ImagesDto> imagesDtos = Lists.newArrayList();
            imageUrlList.add(getImageUrl(avatarUrl));
            final UserAlbumsContentEntity avatarEntity = contentEntities.parallelStream().filter(o -> o.getImageUrl().equals(avatarUrl)).findFirst().orElseGet(UserAlbumsContentEntity::new);
            imagesDtos.add(ImagesDto.builder().imageUrl(getImageUrl(avatarEntity.getImageUrl())).imageCode(avatarEntity.getImageCode()).build());
            for (UserAlbumsContentEntity image : contentEntities) {
                if (StringUtils.isNotEmpty(avatarUrl) && avatarUrl.equals(image.getImageUrl())) {
                    continue;
                }
                imagesDtos.add(ImagesDto.builder().imageUrl(getImageUrl(image.getImageUrl())).imageCode(image.getImageCode()).build());
                imageUrlList.add(getImageUrl(image.getImageUrl()));
            }
//            List<String> imageUrlList = contentEntities.stream().map(entity -> getImageUrl(entity.getImageUrl())).collect(Collectors.toList());
            userInfoDto.setImages(imageUrlList);
            userInfoDto.setImagesV2(imagesDtos);

        }
        List<UserInterestsEntity> interestsList = userInterestsDao.selectByParams(param);
        if (interestsList != null && !interestsList.isEmpty()) {
            List<String> interests = interestsList.stream().map(UserInterestsEntity::getInterest)  // 过滤掉为null的元素
                    .collect(Collectors.toList());
            userInfoDto.setInterests(interests);
        }
        List<UserProfileEntity> userProfiles = userProfileDao.selectByParams(param);
        if (CollUtil.isNotEmpty(userProfiles)) {
            Map<Integer, UserProfileEntity> userProfileMap = userProfiles.stream().collect(Collectors.toMap(UserProfileEntity::getUserProfileType, Function.identity()));
            if (userProfileMap.get(ONE) != null) {
                userInfoDto.setAboutMe(userProfileMap.get(ONE).getAboutMe());
            }
            if (userProfileMap.get(TWO) != null) {
                SocialConnectionsType byCode = SocialConnectionsType.getByCode(userProfileMap.get(TWO).getAboutMe());
                if (byCode != null) {
                    userInfoDto.setSocialConnections(byCode.getValue());
                    userInfoDto.setSocialConnectionsUrl(byCode.getImageUrl());
                }

            }
        }

        // 是否存在招呼语
        final Integer totalGreetings = userGreetingContentDao.queryTotalGreetingByModelUserCode(userCode);
        userInfoDto.setHasGreetingFlag(totalGreetings > 0 ? 1 : 0);
        Date dateTime = ServiceUtils.getDateTime(1, 1);
        userInfoDto.setLocalTime(dateTime);
        //设置扩展信息
        builderExtendInfo(userInfoDto, userEntity, userEntity.getAppCode());

        UserAccountsEntity userAccountsEntity = userAccountsDao.getByUserCode(userInfoDto.getUserCode());
        if (userAccountsEntity != null) {
            userInfoDto.setCID(userAccountsEntity.getAccount());
        }

        // 获取I want / you accept / body shape
        buildUserInfoDto(userCode, userInfoDto);

        return Response.ok(userInfoDto);
    }

    @Override
    public Response<UserInfoDto> getUserByUserCode(String userCode, String appCode) {
        Map<String, Object> param = ServiceUtils.getParams();
        param.put("userCode", userCode);
        UserEntity userEntity = userDao.selectByUserCode(userCode);
        if (userEntity == null) {
            return Response.error(ResultStatus.USER_NOT_EXIST);
        }
        UserInfoDto userInfoDto = userMapper.UserDtoToUserInfo(userEntity);
//        if (userEntity.getGpsPrivilege() == 1) {
//            UserBehaviorGpsEntity userBehaviorGpsEntity = userBehaviorGpsDao.getLastGps(userEntity.getUserCode());
//            if (userBehaviorGpsEntity != null) {
//                userInfoDto.setLat(userBehaviorGpsEntity.getLat());
//                userInfoDto.setLng(userBehaviorGpsEntity.getLng());
//                userInfoDto.setState(userBehaviorGpsEntity.getStateAbbr());
//                userInfoDto.setCity(userBehaviorGpsEntity.getCity());
//            }
//        }
        userInfoDto.setUserValid(userEntity.getStatus().equals(UserStatus.ACTIVE.getType()));
        List<UserAlbumsContentEntity> contentEntities = userAlbumsContentDao.selectByUserCode(userCode, ConstantType.PUBLIC_PHOTO);

        List<UserAlbumsContentEntity> picturesNumber = userAlbumsContentDao.selectByUserCode(userCode, ConstantType.PRIVATE_ALBUM);
        if (CollUtil.isNotEmpty(picturesNumber)) {
            userInfoDto.setPrivateAlbums(picturesNumber.size());
        }
        String avatarUrl = userInfoDto.getAvatarUrl();
        userInfoDto.setAvatarUrl(getImageUrl(avatarUrl));
        if (contentEntities != null && !contentEntities.isEmpty()) {

//            List<String> imageUrlList = contentEntities.stream().map(p -> {
//                int defaultFlag = 0;
//                if (Objects.equals(userInfoDto.getAvatarUrl(), p.getImageUrl())) {
//                    defaultFlag = 1;
//                }
//                return ImagesDto.builder().imageCode(p.getImageCode()).imageUrl(getImageUrl(p.getImageUrl())).defaultFlag(defaultFlag).build();
//            }).sorted(Comparator.comparingInt(ImagesDto::getDefaultFlag).reversed()).map(entity -> getImageUrl(entity.getImageUrl()))
//                    .collect(Collectors.toList());
            List<String> imageUrlList = Lists.newArrayList();
            List<ImagesDto> imagesDtos = Lists.newArrayList();
            imageUrlList.add(getImageUrl(avatarUrl));
            final UserAlbumsContentEntity avatarEntity = contentEntities.parallelStream().filter(o -> o.getImageUrl().equals(avatarUrl)).findFirst().orElseGet(UserAlbumsContentEntity::new);
            imagesDtos.add(ImagesDto.builder().imageUrl(getImageUrl(avatarEntity.getImageUrl())).imageCode(avatarEntity.getImageCode()).build());
            for (UserAlbumsContentEntity image : contentEntities) {
                if (StringUtils.isNotEmpty(avatarUrl) && avatarUrl.equals(image.getImageUrl())) {
                    continue;
                }
                imagesDtos.add(ImagesDto.builder().imageUrl(getImageUrl(image.getImageUrl())).imageCode(image.getImageCode()).build());
                imageUrlList.add(getImageUrl(image.getImageUrl()));
            }
//            List<String> imageUrlList = contentEntities.stream().map(entity -> getImageUrl(entity.getImageUrl())).collect(Collectors.toList());
            userInfoDto.setImages(imageUrlList);
            userInfoDto.setImagesV2(imagesDtos);

        }
        List<UserInterestsEntity> interestsList = userInterestsDao.selectByParams(param);
        if (interestsList != null && !interestsList.isEmpty()) {
            List<String> interests = interestsList.stream().map(UserInterestsEntity::getInterest)  // 过滤掉为null的元素
                    .collect(Collectors.toList());
            userInfoDto.setInterests(interests);
        }
        List<UserProfileEntity> userProfiles = userProfileDao.selectByParams(param);
        if (CollUtil.isNotEmpty(userProfiles)) {
            Map<Integer, UserProfileEntity> userProfileMap = userProfiles.stream().collect(Collectors.toMap(UserProfileEntity::getUserProfileType, Function.identity()));
            if (userProfileMap.get(ONE) != null) {
                userInfoDto.setAboutMe(userProfileMap.get(ONE).getAboutMe());
            }
            if (userProfileMap.get(TWO) != null) {
                SocialConnectionsType byCode = SocialConnectionsType.getByCode(userProfileMap.get(TWO).getAboutMe());
                if (byCode != null) {
                    userInfoDto.setSocialConnections(byCode.getValue());
                    userInfoDto.setSocialConnectionsUrl(byCode.getImageUrl());
                }

            }
        }

        // 是否存在招呼语
        final Integer totalGreetings = userGreetingContentDao.queryTotalGreetingByModelUserCode(userCode);
        userInfoDto.setHasGreetingFlag(totalGreetings > 0 ? 1 : 0);
        Date dateTime = ServiceUtils.getDateTime(1, 1);
        userInfoDto.setLocalTime(dateTime);
        //设置扩展信息
        builderExtendInfo(userInfoDto, userEntity, appCode);

        UserAccountsEntity userAccountsEntity = userAccountsDao.getByUserCode(userInfoDto.getUserCode());
        if (userAccountsEntity != null) {
            userInfoDto.setCID(userAccountsEntity.getAccount());
        }

        // 获取I want / you accept / body shape
        buildUserInfoDto(userCode, userInfoDto);

        return Response.ok(userInfoDto);
    }

    private Map<Integer, List<SelectVal>> getSystemDict() {
        List<String> codes = com.google.api.client.util.Lists.newArrayList();
        codes.add(ConstantType.I_WANT);
        codes.add(ConstantType.YOU_ACCEPT);
        codes.add(ConstantType.BODY_SHAPE);
        final List<SystemDictEntity> dictList = systemDictDao.listByCode(codes);
        if (CollectionUtils.isNotEmpty(dictList)) {
            final List<SelectVal> selectValList = dictList.stream().map(this::buildVo).collect(Collectors.toList());
            return selectValList.stream().collect(Collectors.groupingBy(SelectVal::getType));

        }
        return Maps.newHashMap();
    }


    private void buildUserInfoDto(String userCode, UserInfoDto userInfoDto) {

        final Map<Integer, List<SelectVal>> systemDictMap = getSystemDict();

        final List<UserTagDBO> userTagEntities = userTagDao.listUserTag(userCode);
        if (CollectionUtils.isEmpty(userTagEntities)) {
            buildDefaultRet(userInfoDto, systemDictMap);
            return;
        }

        final Map<Integer, List<UserTagDBO>> groupByType = userTagEntities.stream().collect(Collectors.groupingBy(UserTagDBO::getTagType));
        if (groupByType.containsKey(Integer.valueOf(ConstantType.I_WANT))) {
            userInfoDto.setUserWant(getSelectVals(ConstantType.I_WANT, groupByType.get(Integer.valueOf(ConstantType.I_WANT)), systemDictMap.get(Integer.valueOf(ConstantType.I_WANT)), userInfoDto));
        } else {
            userInfoDto.setUserWant(systemDictMap.get(Integer.valueOf(ConstantType.I_WANT)));
        }
        if (groupByType.containsKey(Integer.valueOf(ConstantType.YOU_ACCEPT))) {
            final List<UserTagDBO> youAcceptList = groupByType.get(Integer.valueOf(ConstantType.YOU_ACCEPT));
            if (CollectionUtils.isNotEmpty(youAcceptList)) {
                userInfoDto.setYouAccept(getSelectVals(ConstantType.YOU_ACCEPT, youAcceptList, systemDictMap.get(Integer.valueOf(ConstantType.YOU_ACCEPT)), userInfoDto));
            }
        } else {
            if (userInfoDto.getGender() != null && GenderEnum.MAN.getType() == userInfoDto.getGender()) {
                userInfoDto.setYouAccept(systemDictMap.get(Integer.valueOf(ConstantType.YOU_ACCEPT)).stream().filter(o -> GenderEnum.MAN.getValue().equals(o.getExtendInfo())).collect(Collectors.toList()));
            } else if (userInfoDto.getGender() != null && GenderEnum.WOMAN.getType() == userInfoDto.getGender()) {
                userInfoDto.setYouAccept(systemDictMap.get(Integer.valueOf(ConstantType.YOU_ACCEPT)).stream().filter(o -> GenderEnum.WOMAN.getValue().equals(o.getExtendInfo())).collect(Collectors.toList()));
            } else {
                userInfoDto.setYouAccept(systemDictMap.get(Integer.valueOf(ConstantType.YOU_ACCEPT)).stream().filter(o -> GenderEnum.MAN.getValue().equals(o.getExtendInfo())).collect(Collectors.toList()));
            }
        }
        if (groupByType.containsKey(Integer.valueOf(ConstantType.BODY_SHAPE))) {
            final List<UserTagDBO> bodyShapeList = groupByType.get(Integer.valueOf(ConstantType.BODY_SHAPE));
            if (CollectionUtils.isNotEmpty(bodyShapeList)) {
                userInfoDto.setBodyShape(getSelectVals(ConstantType.BODY_SHAPE, bodyShapeList, systemDictMap.get(Integer.valueOf(ConstantType.BODY_SHAPE)), userInfoDto));
            }
        } else {
            if (userInfoDto.getGender() != null && GenderEnum.MAN.getType() == userInfoDto.getGender()) {
                userInfoDto.setBodyShape(systemDictMap.get(Integer.valueOf(ConstantType.BODY_SHAPE)).stream().filter(o -> GenderEnum.MAN.getValue().equals(o.getExtendInfo())).collect(Collectors.toList()));
            } else if (userInfoDto.getGender() != null && GenderEnum.WOMAN.getType() == userInfoDto.getGender()) {
                userInfoDto.setBodyShape(systemDictMap.get(Integer.valueOf(ConstantType.BODY_SHAPE)).stream().filter(o -> GenderEnum.WOMAN.getValue().equals(o.getExtendInfo())).collect(Collectors.toList()));
            } else {
                userInfoDto.setBodyShape(systemDictMap.get(Integer.valueOf(ConstantType.BODY_SHAPE)).stream().filter(o -> GenderEnum.MAN.getValue().equals(o.getExtendInfo())).collect(Collectors.toList()));
            }
        }


    }

    @NotNull
    private List<SelectVal> getSelectVals(String type, List<UserTagDBO> userTagList, List<SelectVal> selectVals, UserInfoDto userInfoDto) {
        if (CollectionUtils.isEmpty(userTagList)) {
            return selectVals;
        }
        final List<Integer> userTag = userTagList.stream().map(UserTagDBO::getTagCode).collect(Collectors.toList());

        List<SelectVal> selectValList;
        if (ConstantType.I_WANT.equals(type)) {
            selectValList = selectVals;
        } else {
            if (userInfoDto.getGender() != null && GenderEnum.MAN.getType() == userInfoDto.getGender()) {
                selectValList = selectVals.stream().filter(o -> GenderEnum.MAN.getValue().equals(o.getExtendInfo())).collect(Collectors.toList());
            } else if (userInfoDto.getGender() != null && GenderEnum.WOMAN.getType() == userInfoDto.getGender()) {
                selectValList = selectVals.stream().filter(o -> GenderEnum.WOMAN.getValue().equals(o.getExtendInfo())).collect(Collectors.toList());
            } else {
                selectValList = selectVals.stream().filter(o -> GenderEnum.MAN.getValue().equals(o.getExtendInfo())).collect(Collectors.toList());
            }
        }

        return selectValList.stream().map(o -> {
            if (userTag.contains(Integer.valueOf(String.valueOf(o.getCode())))) {
                o.setSelected(1);
            } else {
                o.setSelected(0);
            }
            return o;
        }).collect(Collectors.toList());
    }

    /**
     * 设置默认值
     */
    private void buildDefaultRet(UserInfoDto userInfoDto, Map<Integer, List<SelectVal>> systemDictMap) {
        userInfoDto.setUserWant(systemDictMap.get(Integer.valueOf(ConstantType.I_WANT)));
        if (userInfoDto.getGender() != null && GenderEnum.MAN.getType() == userInfoDto.getGender()) {
            userInfoDto.setYouAccept(systemDictMap.get(Integer.valueOf(ConstantType.YOU_ACCEPT)).stream().filter(o -> GenderEnum.MAN.getValue().equals(o.getExtendInfo())).collect(Collectors.toList()));
        } else if (userInfoDto.getGender() != null && GenderEnum.WOMAN.getType() == userInfoDto.getGender()) {
            userInfoDto.setYouAccept(systemDictMap.get(Integer.valueOf(ConstantType.YOU_ACCEPT)).stream().filter(o -> GenderEnum.WOMAN.getValue().equals(o.getExtendInfo())).collect(Collectors.toList()));
        } else {
            userInfoDto.setYouAccept(systemDictMap.get(Integer.valueOf(ConstantType.YOU_ACCEPT)).stream().filter(o -> GenderEnum.MAN.getValue().equals(o.getExtendInfo())).collect(Collectors.toList()));
        }
        if (userInfoDto.getGender() != null && GenderEnum.MAN.getType() == userInfoDto.getGender()) {
            userInfoDto.setBodyShape(systemDictMap.get(Integer.valueOf(ConstantType.BODY_SHAPE)).stream().filter(o -> GenderEnum.MAN.getValue().equals(o.getExtendInfo())).collect(Collectors.toList()));
        } else if (userInfoDto.getGender() != null && GenderEnum.WOMAN.getType() == userInfoDto.getGender()) {
            userInfoDto.setBodyShape(systemDictMap.get(Integer.valueOf(ConstantType.BODY_SHAPE)).stream().filter(o -> GenderEnum.WOMAN.getValue().equals(o.getExtendInfo())).collect(Collectors.toList()));
        } else {
            userInfoDto.setBodyShape(systemDictMap.get(Integer.valueOf(ConstantType.BODY_SHAPE)).stream().filter(o -> GenderEnum.MAN.getValue().equals(o.getExtendInfo())).collect(Collectors.toList()));
        }
    }

    private SelectVal buildVo(UserTagDBO userTagDBO, Integer selected) {
        return SelectVal.builder().code(Long.valueOf(String.valueOf(userTagDBO.getTagCode()))).value(userTagDBO.getTagName()).selected(selected).build();
    }

    private SelectVal buildVo(SystemDictEntity dict) {
        return SelectVal.builder().code(Long.valueOf(String.valueOf(dict.getId()))).type(Integer.valueOf(dict.getDictCode())).iconUrl(dict.getPhotoUrl()).value(dict.getDictName()).selected(0).extendInfo(dict.getExtendInfo()).build();
    }


    /**
     * 返回扩展信息
     */
    public void builderExtendInfo(UserInfoDto userInfoDto, UserEntity user, String appCode) {
        String extendInfo = user.getExtendInfo();
        appCode = StringUtils.isEmpty(appCode) ? user.getAppCode() : appCode;
        try {
            if (StringUtils.isNotEmpty(extendInfo)) {
                ExtendInfoDto extendInfoDto = JSONUtil.toBean(user.getExtendInfo(), ExtendInfoDto.class);
                if (extendInfoDto.getConstellation() != null) {
                    ConstellationEnums zodiac = ConstellationEnums.getZodiacById(extendInfoDto.getConstellation());
                    userInfoDto.setConstellation(zodiac.getId());
                    userInfoDto.setConstellationName(zodiac.getName());
                    userInfoDto.setConstellationIcon(zodiac.getIcon());
                }
                if (StringUtils.isNotEmpty(extendInfoDto.getHeight())) {
                    userInfoDto.setHeight(ServiceUtils.feetInchesToCentimeters(extendInfoDto.getHeight()));
                    userInfoDto.setInchHeight(extendInfoDto.getHeight());
                    userInfoDto.setHideHeight(extendInfoDto.isHideHeight());
                }
                List<Integer> turnOnsList = extendInfoDto.getTurnOnsList();
                if (CollUtil.isEmpty(extendInfoDto.getTurnOnsList())) {
                    turnOnsList = new ArrayList<>();
                }
                List<UserTurnOnsEntity> userTurnOnsEntities = userTurnOnsDao.listUserTurnOns(appCode);
                List<UserTurnOnsDto> userTurnOnsDtoList = new ArrayList<>();
                for (UserTurnOnsEntity userTurnOns : userTurnOnsEntities) {
                    UserTurnOnsDto userTurnOnsDto = new UserTurnOnsDto();
                    if (turnOnsList.contains(userTurnOns.getId().intValue())) {
                        userTurnOns.setSelected(ONE);
                    }
                    BeanUtil.copyProperties(userTurnOns, userTurnOnsDto);
                    userTurnOnsDto.setTurnOnsCode(userTurnOns.getId());
                    userTurnOnsDtoList.add(userTurnOnsDto);
                }
                userInfoDto.setTurnOnsList(userTurnOnsDtoList);

            } else {
                List<UserTurnOnsEntity> userTurnOnsEntities = userTurnOnsDao.listUserTurnOns(appCode);
                List<UserTurnOnsDto> userTurnOnsList = userTurnOnsEntities.stream().map(userTurnOns -> {
                    UserTurnOnsDto userTurnOnsDto = new UserTurnOnsDto();
                    BeanUtil.copyProperties(userTurnOns, userTurnOnsDto);
                    userTurnOnsDto.setTurnOnsCode(userTurnOns.getId());
                    return userTurnOnsDto;
                }).collect(Collectors.toList());
                userInfoDto.setTurnOnsList(userTurnOnsList);
            }
        } catch (Exception e) {
            logger.error("builderExtendInfo:{}", extendInfo, e);
        }
    }

    @Override
    public Response<List<UserInfoDto>> getUserByUserType(String userType) {
        Map<String, Object> param = ServiceUtils.getParams();
        param.put("userType", userType);
        List<UserEntity> userEntities = userDao.selectByParams(param);
        if (CollUtil.isNotEmpty(userEntities)) {
            List<UserInfoDto> userInfoDtoList = new ArrayList<>();
            for (UserEntity user : userEntities) {
                UserInfoDto userInfoDto = userMapper.UserDtoToUserInfo(user);
                userInfoDto.setAvatarUrl(getImageUrl(userInfoDto.getAvatarUrl()));
                userInfoDtoList.add(userInfoDto);
            }
            return Response.ok(userInfoDtoList);
        }
        return Response.error(ResultStatus.ILLEGAL_USER_TYPE);
    }

    @Override
    public Response<UserBaseDto> getUserBaseInfo(String userCode) {
        Map<String, Object> param = ServiceUtils.getParams();
        param.put("userCode", userCode);
        List<UserEntity> entities = userDao.selectByParams(param);
        if (CollUtil.isNotEmpty(entities)) {
            UserEntity userEntity = entities.get(0);

            final String avatarUrl = userEntity.getAvatarUrl();
            userEntity.setAvatarUrl(getImageUrl(avatarUrl));
            final UserBaseDto userBaseDto = userMapper.UserToUserBase(userEntity);
            userBaseDto.setGmtCreate(userEntity.getGmtCreate());
            userBaseDto.setNewUserFlag(userEntity.getGmtCreate().after(DateUtil.beginOfDay(new Date())));
            userBaseDto.setChannel(userEntity.getChannel());
            return Response.ok(userBaseDto);
        }
        return Response.error(ResultStatus.USER_NOT_EXIST);
    }

    @Override
    public Response<UserAccountDto> getUserAccount(String userCode) {
        Map<String, Object> params = ServiceUtils.getParams();
        params.put("userCode", userCode);
        UserAccountDto userAccountDto = new UserAccountDto();
        List<UserAccountsEntity> accountsEntities = userAccountsDao.selectByParams(params);
        if (accountsEntities != null && !accountsEntities.isEmpty()) {
            for (UserAccountsEntity userAccount : accountsEntities) {
                LoginType loginType = LoginType.fromType(userAccount.getAccountType());
                switch (loginType) {
                    case GOOGLE:
                        userAccountDto.setGoogleBind(true);
                        userAccountDto.setGoogleName(StringUtils.isNotEmpty(userAccount.getAccountName()) ? userAccount.getAccountName() : "Connected");
                        break;
                    case FACE_BOOK:
                        userAccountDto.setFacebookBind(true);
                        userAccountDto.setFacebookName(StringUtils.isNotEmpty(userAccount.getAccountName()) ? userAccount.getAccountName() : "Connected");
//                        userAccountDto.setFacebook(userAccount.getAccount());
                        break;
                    case MOBILE:
                        List<UserEntity> entities = userDao.selectByParams(params);
                        if (CollUtil.isNotEmpty(entities)) {
                            userAccountDto.setMobileBind(true);
                            userAccountDto.setMobile(entities.get(0).getMobile());
                        }

                        break;
                    default:
                        return Response.error(ResultStatus.INVALID_ACCOUNT_TYPE);
                }
            }
            return Response.ok(userAccountDto);
        }
        return Response.error(ResultStatus.NO_ACCOUNT);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response<String> accountBind(UserAccountDto userAccountDto, String userCode) {
        UserAccountsEntity userAccount = new UserAccountsEntity();
        userAccount.setUserCode(userCode);
        userAccount.setAccountType(userAccountDto.getAccountType());
        LoginType loginType = LoginType.fromType(userAccountDto.getAccountType());
        switch (loginType) {
            case GOOGLE:
            case FACE_BOOK:
                userAccount.setAccount(userAccountDto.getAccount());
                userAccount.setAccountName(userAccountDto.getUserName());
                break;
            case MOBILE:
                userAccount.setAccount(userAccountDto.getAccount());
                break;
            default:
                return Response.error(ResultStatus.INVALID_ACCOUNT_TYPE);
        }
        //绑定账号为空则抛出异常
        if (StringUtils.isEmpty(userAccount.getAccount())) {
            return Response.error(ResultStatus.BINDING_ACCOUNT_EMPTY);
        }
        Map<String, Object> accountParam = ServiceUtils.getParams();
        accountParam.put("account", userAccount.getAccount());
        accountParam.put("deleted", 0);
        List<UserAccountsEntity> userAccountsEntities = userAccountsDao.selectByParams(accountParam);
        if (CollUtil.isNotEmpty(userAccountsEntities)) {
            // 如果该账户被其他用户绑定则返回
            final boolean existsOtherAccount = userAccountsEntities.stream().anyMatch(o -> !Objects.equals(o.getUserCode(), userCode));
            if (existsOtherAccount) {
                return Response.error(ResultStatus.ACCOUNT_IS_BOUND);
            }
        }
        accountParam = ServiceUtils.getParams();
        accountParam.put("userCode", userCode);
        accountParam.put("accountType", userAccountDto.getAccountType());
        userAccountsEntities = userAccountsDao.selectByParams(accountParam);
        if (CollectionUtils.isNotEmpty(userAccountsEntities) && !LoginType.MOBILE.equals(loginType)) {
            //如果用户已存在相同类型的绑定账号则返回
            return Response.error(ResultStatus.DUPLICATE_ACCOUNT_TYPE);
        } else if (CollUtil.isNotEmpty(userAccountsEntities) && LoginType.MOBILE.equals(loginType)) {
            Response<String> stringResponse = removeAccount(userCode, userAccountDto.getAccountType());
            if (!stringResponse.isSuccess()) {
                return stringResponse;
            }
        }
        if (LoginType.MOBILE.equals(loginType)) {
            List<UserEntity> entities = userDao.selectByParams(accountParam);
            UserEntity user = new UserEntity();
            user.setId(entities.get(0).getId());
            user.setMobile(userAccountDto.getMobile());
            userDao.updateByPrimaryKey(user);
        }
        userAccountsDao.insert(userAccount);
        return Response.ok("Binding succeeded");
    }

    @Override
    public Response<String> removeAccount(String userCode, Integer accountType) {
        Map<String, Object> accountParam = ServiceUtils.getParams();
        accountParam.put("userCode", userCode);

        List<UserAccountsEntity> userAccounts = userAccountsDao.selectByParams(accountParam);
        if (CollUtil.isNotEmpty(userAccounts) && userAccounts.size() > ONE) {
            accountParam.put("accountType", accountType);
            userAccountsDao.deleteByUserCode(accountParam);
            return Response.ok();
        } else {
            return Response.error(ResultStatus.ONLY_ONE_ACCOUNT);
        }
    }

    @Override
    public Response<String> changeBindAccount(String userCode, Integer accountType, String mobile) {

        final UserEntity currentUser = userDao.selectByUserCode(userCode);
        if (Objects.isNull(currentUser)) {
            return Response.error(ResultStatus.USER_NOT_EXIST);
        }

        // 账号已绑定手机号码， 并且绑定的手机号码与待绑定的手机号码不一致为换绑
        Map<String, Object> accountParam = ServiceUtils.getParams();
        accountParam.put("userCode", userCode);
        List<UserAccountsEntity> userAccounts = userAccountsDao.selectByParams(accountParam);
        // 换绑
        if (StringUtils.isNotEmpty(currentUser.getMobile()) && !Objects.equals(currentUser.getMobile(), mobile)) {
            accountParam.put("accountType", accountType);
            userAccountsDao.deleteByUserCode(accountParam);
            return Response.ok();
        }
        // 解绑
        else {
            if (CollUtil.isNotEmpty(userAccounts) && userAccounts.size() > ONE) {
                accountParam.put("accountType", accountType);
                userAccountsDao.deleteByUserCode(accountParam);
                return Response.ok();
            } else {
                return Response.error(ResultStatus.ONLY_ONE_ACCOUNT);
            }
        }


    }

    @Override
    public Response<String> removeUser(String userCode) {
        userDao.delete(userCode);
        Map<String, Object> accountParam = ServiceUtils.getParams();
        accountParam.put("userCode", userCode);
        userAccountsDao.deleteByUserCode(accountParam);

        try {
            userChatterMappingDao.deleteByModelUserCode(userCode);
        } catch (Exception e) {
            logger.error("== 删除用户的时候，同事删除绑定关系 ==,userCode:{}", userCode, e);
        }
        return Response.ok();
    }

    @Override
    public Response<String> removeUser(String userCode, String email) {
        Map<String, Object> accountParam = ServiceUtils.getParams();
        accountParam.put("email", email);
        accountParam.put("userCode", userCode);
        List<UserEntity> userEntities = userDao.selectByParams(accountParam);
        if (CollUtil.isNotEmpty(userEntities)) {
            userDao.deleteByPrimaryKey(userEntities.get(0).getId());
            userAccountsDao.deleteByUserCode(accountParam);
        }
        return Response.ok();
    }

    @Override
    public Response<String> removeUserAccount(String mobile, String email) {
        Map<String, Object> accountParam = ServiceUtils.getParams();
        if (StringUtils.isNotEmpty(mobile)) {
            accountParam.put("mobile", mobile);
        }
        if (StringUtils.isNotEmpty(email)) {
            accountParam.put("email", email);
        }
        if (accountParam.isEmpty()) {
            return Response.ok();
        }

        List<UserEntity> userEntities = userDao.selectByParams(accountParam);
        if (CollUtil.isNotEmpty(userEntities)) {
            for (UserEntity en : userEntities) {
                userDao.deleteByPrimaryKey(en.getId());
                userAccountsDao.removeByUserCode(en.getUserCode());
            }
        }


        return Response.ok();
    }

    @Override
    public Response<UserBaseDto> getUserBaseInfoByEmail(String email) {
        Map<String, Object> accountParam = ServiceUtils.getParams();
        accountParam.put("email", email);
        List<UserEntity> userEntities = userDao.selectByParams(accountParam);
        if (CollUtil.isNotEmpty(userEntities)) {
            UserBaseDto userBaseDto = userMapper.UserToUserBase(userEntities.get(0));
            userBaseDto.setAvatarUrl(getImageUrl(userBaseDto.getAvatarUrl()));
            return Response.ok(userBaseDto);
        }
        return Response.ok();
    }


    /**
     * 修改用户在线状态
     */
    @Override
    public Integer updateOnline(String userCode) {
        UserEntity user = userDao.selectByUserCode(userCode);
        if (Objects.isNull(user)) {
            return 0;
        }
        logger.info("== 更新用户在线时间 ==,userCode:{},userType:{}", userCode, user.getUserType());
        user.setOnline(OnlineStatus.ONLINE_STATUS.getType());
        user.setOnlineTimestamp(Long.valueOf(Calendar.getInstance().getTimeInMillis()).toString());
        if (Objects.isNull(user.getRegisterDate()) && UserStatus.ACTIVE.getType() == user.getStatus()) {
            if (user.getGmtCreate() != null) {
                user.setRegisterDate(user.getGmtCreate());
            }
        }
        userDao.update(user);
        logger.info("== 更新用户在线时间 成功==,userCode:{}", userCode);


        try {
            // 添加日活记当表
            userOnlineDailyLogDao.addUserOnlineDailyLog(userCode, user.getUserType());

            // 更新主播绑定的model在线状态
            if (UserType.CHATTER.getType() == user.getUserType()) {

                final List<UserChatterMappingEntity> userChatterMappingEntities = userChatterMappingDao.queryByChatterUserCode(user.getUserCode());

                if (CollectionUtils.isEmpty(userChatterMappingEntities)) {
                    return 1;
                }

                final List<String> modelUserCodes = userChatterMappingEntities.parallelStream().map(UserChatterMappingEntity::getModelUserCode).distinct().collect(Collectors.toList());
                userDao.batchUpdateUserOnlineStatus(modelUserCodes, OnlineStatus.ONLINE_STATUS.getType(), Long.valueOf(Calendar.getInstance().getTimeInMillis()).toString());
            }
        } catch (Exception e) {
            logger.error("== 更新用户在线时间 chatter绑定的model事件 ==,userCode:{}", userCode, e);
        }

        return 1;
    }

    private void pushOnlineStatusToMeboo(UserEntity userEntity, OnlineStatus onlineStatus) {

        /**
         *  1) 推送在线状态到应用端（接收用户为在线用户）
         *  2) 根据用户所处的位置进行相应推送，分别推送到会话列表、match列表、wlm列表、首页推送
         *  3) 推送目标代码：
         *  S20002:  首页在线状态
         *  S20003:  WLM在线状态
         *  S20004:  NEW MATCH在线状态
         *  S20005:  CHAT LIST在线状态
         */
        // 会话列表
        final List<UserConversationDBO> conversationList = userConversationDao.queryOnlineUsers(userEntity.getUserCode());
        if (CollectionUtils.isNotEmpty(conversationList)) {
            conversationList.forEach(o -> {
                pushMessage(o.getUserCode(), o.getUserCodeFriend(), onlineStatus, userEntity.getUserType(), "S20005");
            });
        }

        /*// match列表
        final List<UserWlmEntity> matchedList = userWlmDao.queryOnlineMatchedList(userEntity.getUserCode());
        if (CollectionUtils.isNotEmpty(matchedList)) {
            matchedList.forEach(o -> {
                pushMessage(o.getUserCode(), o.getUserCodeWlm(), onlineStatus, "S20004");
            });
        }

        // wlm列表
        final List<UserWlmEntity> wlmList = userWlmDao.queryOnlineWlmList(userEntity.getUserCode());
        if (CollectionUtils.isNotEmpty(wlmList)) {
            wlmList.forEach(o -> {
                pushMessage(o.getUserCode(), o.getUserCodeWlm(), onlineStatus, "S20003");
            });
        }

        // 首页推送
        final List<UserPreHomepageEntity> homepageList = userPreHomepageDao.queryOnlineUser(userEntity.getUserCode());
        if (CollectionUtils.isNotEmpty(homepageList)) {
            homepageList.forEach(o -> {
                pushMessage(o.getUserCodeWlm(), o.getUserCode(), onlineStatus, "S20002");
            });
        }*/

    }

    private void pushMessage(String fromUseCode, String toUserCode, OnlineStatus onlineStatus, Integer userType, String target) {
        pushEventBus.post(buildEvent(fromUseCode, toUserCode, onlineStatus, userType, target));
    }

    private Event buildEvent(String fromUseCode, String toUserCode, OnlineStatus onlineStatus, Integer userType, String target) {
        Map<String, Object> params = Maps.newHashMap();
        params.put("type", ParameterTypeEnum.PUSH_MODEL_ONLINE.getId());
        params.put("target", target);
        params.put("online", onlineStatus.getType());
        params.put("userType", userType);

        return Event.builder().eventActionEnum(ActionEnum.PUSH_MSG).fromUserCode(fromUseCode).toUserCode(toUserCode).app(AppEnum.MEBOO).content(JSONObject.toJSONString(params)).build();

    }


    /**
     * 修改用户在线状态
     */
    @Resource
    AsyncEventBus pushEventBus;
    @Resource
    UserConversationDao userConversationDao;

    /**
     * 20230927：用户下线不更新状态，只更新时间OnlineTimestamp字段
     */
    @Override
    public Integer updateOffline(String userCode) {
        logger.info("== 用户下线 ==,userCode:{}", userCode);
        UserEntity user = userDao.selectByUserCode(userCode);
        if (Objects.isNull(user)) {
            return 0;
        }
//        user.setOnline(OnlineStatus.OFFLINE_STATUS.getType());
        user.setOnlineTimestamp(Long.valueOf(Calendar.getInstance().getTimeInMillis()).toString());
        logger.info("== 更新用户用户下线成功==,userCode:{}", userCode);

//        try {
//            if (UserType.CHATTER.getType() == user.getUserType()) {
//                final List<UserEntity> allModelsByChatterUserCode = userDao.getAllModelsByChatterUserCode(user.getUserCode());
//                if (CollectionUtils.isEmpty(allModelsByChatterUserCode)) {
//                    return 1;
//                }
//                for (UserEntity model : allModelsByChatterUserCode) {
//                    model.setOnline(OnlineStatus.ONLINE_STATUS.getType());
//                    model.setOnlineTimestamp(Long.valueOf(Calendar.getInstance().getTimeInMillis()).toString());
//                    userDao.updateByPrimaryKey(model);
//                    pushOnlineStatusToMeboo(model, OnlineStatus.OFFLINE_STATUS);
//                }
//
//            } else if (UserType.CHATTER_MODEL.getType() == user.getUserType()) {
//                pushOnlineStatusToMeboo(user, OnlineStatus.OFFLINE_STATUS);
//            } else if (UserType.NORMAL_USER.getType() == user.getUserType()){
//                pushOnlineStatusToMechat(userCode, OnlineStatus.OFFLINE_STATUS, AppEnum.MECHAT);
//            }
//        } catch (Exception e) {
//            logger.error("== 更新用户下线时间 chatter绑定的model事件 ==,userCode:{}", userCode, e);
//        }

        return userDao.update(user);
    }


    private void pushOnlineStatusToMechat(String userCode, OnlineStatus onlineStatus, AppEnum appEnum) {
        try {
            final List<UserConversationDBO> conversationDBOS = userConversationDao.queryOnlineModels(userCode);
            if (CollectionUtils.isNotEmpty(conversationDBOS)) {
                for (UserConversationDBO conversation : conversationDBOS) {
                    Map<String, Object> params = Maps.newHashMap();
                    params.put("type", ParameterTypeEnum.PUSH_MODEL_ONLINE.getId());
                    params.put("target", "M20002");
                    params.put("online", onlineStatus.getType());
                    params.put("token", conversation.getChatterUserCode());
                    params.put("userCode", userCode);
                    params.put("modelUserCode", conversation.getUserCodeFriend());

                    final Event event = Event.builder().eventActionEnum(ActionEnum.PUSH_MSG).fromUserCode(userCode).toUserCode(conversation.getChatterUserCode()).app(appEnum).content(JSONObject.toJSONString(params)).build();
                    pushEventBus.post(event);

                }
            }
        } catch (Exception e) {
            logger.error("pushOnlineStatusError, UserCode:{}", userCode);
        }
    }


    /**
     * 创建用户相册
     *
     * @param userCode
     * @param albumType 1 个人照片、2 公开相册、3 私密相册
     * @return
     */
    @Override
    public Response<AlbumDto> createAlbums(String userCode, Integer albumType) {

        final UserAlbumsEntity userAlbumsEntity = userAlbumsDao.selectByType(userCode, albumType);
        if (Objects.nonNull(userAlbumsEntity)) {
            Response.ok(AlbumDto.builder().userCode(userCode).albumCode(userAlbumsEntity.getAlbumCode()).build());
        }

        UserAlbumsEntity entity = new UserAlbumsEntity();
        entity.setAlbumCode(String.valueOf(UserSnowflake.getInstance().nextId()));
        entity.setStatus(AlbumsStatus.ACTIVE.getType());
        entity.setUserCode(userCode);
        entity.setType(albumType);
        userAlbumsDao.insert(entity);


        return Response.ok(AlbumDto.builder().albumCode(entity.getAlbumCode()).userCode(userCode).build());
    }

    /**
     * 照片存储
     *
     * @param userCode
     * @param albumType   1 个人照片、2 公开相册、3 私密相册
     * @param imageCode   照片码
     * @param url         照片url
     * @param albumsCode  相册编码
     * @param videoLength 视频长度，添加照片该字段无值
     * @return
     */
    @Override
    public Response<ImagesObjDto> addImageToAlbums(String userCode, Integer albumType, String imageCode, String url, String albumsCode, Integer videoLength) {

        ImagesObjDto dto = ImagesObjDto.builder().build();
        UserAlbumsContentEntity userAlbumsContentEntity = userAlbumsContentDao.selectByImageCode(imageCode);
        if (Objects.isNull(userAlbumsContentEntity)) {
            userAlbumsContentEntity = new UserAlbumsContentEntity();
            userAlbumsContentEntity.setAlbumCode(albumsCode);
            userAlbumsContentEntity.setImageCode(String.valueOf(UserSnowflake.getInstance().nextId()));
            userAlbumsContentEntity.setImageUrl(url);
            userAlbumsContentEntity.setStatus(AlbumsStatus.ACTIVE.getType());
            if (Objects.isNull(videoLength)) {
                userAlbumsContentEntity.setType(ImageType.IMAGE.getType());
            } else {
                userAlbumsContentEntity.setVideoLength(videoLength);
                userAlbumsContentEntity.setType(ImageType.VIDEO.getType());
            }
            userAlbumsContentDao.insert(userAlbumsContentEntity);

            BeanUtils.copyProperties(userAlbumsContentEntity, dto);

            return Response.ok(dto);
        }

        // 指定相册中存在该照片，不作处理
        if (Objects.equals(userAlbumsContentEntity.getImageCode(), imageCode)) {
            BeanUtils.copyProperties(userAlbumsContentEntity, dto);
            return Response.ok(dto);
        }

        final UserAlbumsEntity albums = userAlbumsDao.selectByType(userCode, albumType);
        if (Objects.isNull(albums)) {
            return Response.error("The albums not exists");
        }

        // 更换到指定相册
        userAlbumsContentEntity.setAlbumCode(albums.getAlbumCode());
        userAlbumsContentEntity.setStatus(AlbumsStatus.ACTIVE.getType());
        if (Objects.isNull(videoLength)) {
            userAlbumsContentEntity.setType(ImageType.IMAGE.getType());
        } else {
            userAlbumsContentEntity.setVideoLength(videoLength);
            userAlbumsContentEntity.setType(ImageType.VIDEO.getType());
        }
        userAlbumsContentDao.updateByPrimaryKey(userAlbumsContentEntity);
        BeanUtils.copyProperties(userAlbumsContentEntity, dto);
        return Response.ok(dto);
    }

    @Override
    public Response removeImageFromAlbums(String userCode, String imageCode, String albumsCode) {

        UserAlbumsContentEntity userAlbumsContentEntity = userAlbumsContentDao.selectByImageCode(imageCode);
        if (Objects.isNull(userAlbumsContentEntity)) {
            return Response.ok();
        }
        userAlbumsContentEntity.setDeleted(Boolean.TRUE);
        userAlbumsContentDao.updateByPrimaryKey(userAlbumsContentEntity);

        return Response.ok();
    }

    /**
     * 获取用户相册
     *
     * @param userCode
     * @param albumType 1 个人照片、2 公开相册、3 私密相册
     * @return
     */
    @Override
    public Response<AlbumDto> getUserImages(String userCode, Integer albumType) {

        final AlbumsType albumsType = AlbumsType.fromType(albumType);
        if (Objects.isNull(albumsType)) {
            logger.error("未查询到指定的相册类型, userCode:{}, albumType:{}", userCode, albumType);
            return Response.error(ResultStatus.ILLEGAL_PARAMS, "userCode:" + userCode + " albumType:" + albumType);
        }

        // 获取用户信息
        final UserEntity userEntity = userDao.selectByUserCode(userCode);
        if (Objects.isNull(userEntity)) {
            logger.error("未查询到用户, userCode:{}", userCode);
            return Response.error(ResultStatus.USER_NOT_EXIST, "User not found, userCode:{}" + userCode);
        }
        final List<UserAlbumsEntity> userAlbumsEntities = userAlbumsDao.selectByUserCode(userCode);
        if (CollectionUtils.isEmpty(userAlbumsEntities)) {
            return Response.ok(AlbumDto.builder().build());
        }

        final String albumCode = userAlbumsEntities.stream().filter(o -> Objects.equals(albumType, o.getType())).map(UserAlbumsEntity::getAlbumCode).findFirst().orElse("");

        final List<UserAlbumsContentEntity> userAlbumsContentEntities = userAlbumsContentDao.selectByAlbumCode(albumCode);

        final List<ImagesDto> images = userAlbumsContentEntities.stream().filter(Objects::nonNull).map(p -> ImagesDto.builder().imageUrl(getImageUrl(p.getImageUrl())).imageCode(p.getImageCode()).type(getType(p.getType(), p.getImageUrl())).videoLength(p.getVideoLength()).build()).collect(Collectors.toList());

        return Response.ok(AlbumDto.builder().albumCode(albumCode).images(images).userCode(userCode).build());
    }

    private Integer getType(Integer type, String url) {
        if (Objects.nonNull(type)) {
            return type;
        }
        if (StringUtils.isNotEmpty(url)) {
            if (url.contains(".jpg") || url.contains(".png")) {
                return ImageType.IMAGE.getType();
            }
        }
        return null;
    }


    /**
     * 添加设备信息
     *
     * @param deviceInfoDto 设备信息
     * @return
     */
    @Override
    public Response addDeviceInfo(DeviceInfoDto deviceInfoDto) {

        if (Objects.isNull(deviceInfoDto)) {
            return Response.error("The parameter deviceInfo should be empty!");
        }
        if (Objects.isNull(deviceInfoDto.getGps()) && CollectionUtils.isEmpty(deviceInfoDto.getWifilist())) {
            return Response.error("The gps and wifi validation failed, both gps and wifi are empty!");
        }

        if (Objects.nonNull(deviceInfoDto.getGps())) {
            final GpsDto gpsDto = deviceInfoDto.getGps();
            userBehaviorGpsDao.addGps(deviceInfoDto.getUserCode(), gpsDto.getState(), null, gpsDto.getCity(), gpsDto.getLng(), gpsDto.getLat());


            // 更新地理位置授权
            final UserEntity user = userDao.selectByUserCode(deviceInfoDto.getUserCode());
            user.setGpsPrivilege(HAS_GRANT_PRIVILEGE);
            userDao.updateByPrimaryKey(user);

        }
        if (CollectionUtils.isNotEmpty(deviceInfoDto.getWifilist())) {
            final List<WifiDto> wifiList = deviceInfoDto.getWifilist();
            final List<UserBehaviorWifiEntity> wifiEntities = wifiList.stream().map(o -> {
                UserBehaviorWifiEntity wifiEntity = new UserBehaviorWifiEntity();
                BeanUtils.copyProperties(o, wifiEntity);
                wifiEntity.setUserCode(deviceInfoDto.getUserCode());
                return wifiEntity;
            }).collect(Collectors.toList());
            userBehaviorWifiDao.batchInsertWifi(wifiEntities);
        }

        return Response.ok();
    }


    /**
     * 添加聊天会话信息
     *
     * @param conversationDto 接收到的IM平台聊天会话信息
     * @return
     */

    @Override
    public Response<ConversationDto> addUserConversation(ConversationDto conversationDto) {

        // 查找会话ID
        final List<UserConversationEntity> userConversationEntities = getUserConversationEntities(conversationDto.getFromUserId(), conversationDto.getTargetId());
        if (CollectionUtils.isNotEmpty(userConversationEntities)) {
            return Response.ok(buildConversationDto(userConversationEntities.get(0)));
        }

        // 不存在则添加会话
        UserConversationEntity userConversationEntity = new UserConversationEntity();
        userConversationEntity.setUserCode(conversationDto.getFromUserId());
        userConversationEntity.setUserCodeFriend(conversationDto.getToUserId());
        userConversationEntity.setConversationType(Integer.valueOf(conversationDto.getConversationType()));
        // 单聊时，会话ID 直接使用对方的用户ID, 在群组、聊天室、超级群中，为对应的群组、聊天室、超级群ID
        userConversationEntity.setTargetId(conversationDto.getToUserId());
        userConversationDao.insert(userConversationEntity);
        userConversationChatterDao.insertConversation(userConversationEntity);

        return Response.ok(buildConversationDto(userConversationEntity));
    }

    /**
     * 查询聊天会话信息
     *
     * @param targetId 聊天会话ID, 单聊时为对方的用户ID
     * @return 返回聊天会话信息
     */
    @Override
    public Response<ConversationDto> getConversation(String fromUserId, String targetId) {

        // 查找会话ID
        final List<UserConversationEntity> userConversationEntities = getUserConversationEntities(fromUserId, targetId);
        if (CollectionUtils.isEmpty(userConversationEntities)) {
            return Response.ok();
        }
        return Response.ok(buildConversationDto(userConversationEntities.get(0)));
    }

    private ConversationDto buildConversationDto(UserConversationEntity entity) {
        return ConversationDto.builder().fromUserId(entity.getUserCode()).targetId(entity.getTargetId()).conversationType(String.valueOf(entity.getConversationType())).toUserId(entity.getUserCodeFriend()).build();
    }

    private List<UserConversationEntity> getUserConversationEntities(String fromUserId, String targetId) {
        Map<String, Object> params = Maps.newHashMap();
        params.put("userCode", fromUserId);
        params.put("targetId", targetId);
        return userConversationDao.selectByParams(params);
    }

    /**
     * 消息存储
     *
     * @param receiveMessageDto 接收到的IM平台聊天消息
     * @return
     */
    public static final long EFFECTIVE_IN_48_HOURS = 60 * 60 * 48L;

    @Override
    public Response receiveMessage(ReceiveMessageDto receiveMessageDto) {

        // 单聊时，会话ID为对方的用户ID，第一个参数为当前用户ID, 第二个参数为会话ID
        String conversationID = redisClient.get(RedisKey.CHAT_CONVERSATION, receiveMessageDto.getFromUserId(), receiveMessageDto.getToUserId());
        // 不存在会话，则添加会话信息
        if (StringUtils.isEmpty(conversationID)) {
            final ConversationDto conversationDto = ConversationDto.builder().conversationType(receiveMessageDto.getChannelType()).fromUserId(receiveMessageDto.getFromUserId()).toUserId(receiveMessageDto.getToUserId()).targetId(receiveMessageDto.getToUserId()).build();
            addUserConversation(conversationDto);
            redisClient.set(RedisKey.CHAT_CONVERSATION, receiveMessageDto.getToUserId(), EFFECTIVE_IN_48_HOURS, receiveMessageDto.getFromUserId(), receiveMessageDto.getToUserId());
        }

        // 消息存储
        UserMsgEntity msgEntity = new UserMsgEntity();
        msgEntity.setMsgId(receiveMessageDto.getMsgUID());
        msgEntity.setFromUserCode(receiveMessageDto.getFromUserId());
        msgEntity.setToUserCode(receiveMessageDto.getToUserId());
        msgEntity.setMsgType(receiveMessageDto.getObjectName());
        msgEntity.setContent(receiveMessageDto.getContent());
        msgEntity.setSource(receiveMessageDto.getSource());
        userMsgDao.insert(msgEntity);
        return Response.ok();
    }

    @Override
    public Integer offlineByUserCodeList(Set<String> set, OnlineStatus onlineStatus) {
        if (onlineStatus.equals(OnlineStatus.OFFLINE_STATUS)) {
            return userDao.offlineByUserCodeList(set);
        } else {
            return userDao.onlineByUserCodeList(set);
        }
    }

    private String getImageUrl(String url) {
        return ImagePrefixUtils.getFullImageUrl(url);
    }


    /**
     * @param userCode 用户码
     * @param type     1、新增记录、2添加离线时间
     */
    @Override
    public void saveOrUpdateChatOnlineRecord(String userCode, int type) {
        UserChatOnlineRecordEntity userChatOnlineRecordEntity = new UserChatOnlineRecordEntity();
        try {
            Map<String, Object> params = ServiceUtils.getParams();
            params.put("userCode", userCode);
            //查询离线时间为空的chat用户
            List<UserChatOnlineRecordEntity> userChatOnlineRecordEntities = chatOnlineRecordDao.selectOfflineChat(params);
            if (type == ONE) {
                //当不存在离线时间为空的记录时新增记录
                if (CollUtil.isEmpty(userChatOnlineRecordEntities)) {
                    userChatOnlineRecordEntity.setUserCode(userCode);
                    userChatOnlineRecordEntity.setOnlineTime(new Date());
                    chatOnlineRecordDao.insert(userChatOnlineRecordEntity);
                }
            } else {
                if (CollUtil.isNotEmpty(userChatOnlineRecordEntities)) {
                    userChatOnlineRecordEntity = userChatOnlineRecordEntities.get(0);
                    userChatOnlineRecordEntity.setOfflineTime(new Date());
                    chatOnlineRecordDao.updateByPrimaryKey(userChatOnlineRecordEntity);
                }
            }
        } catch (Exception e) {
            logger.error("saveOrUpdateChatOnlineRecord error,params:{}", JSONUtil.toJsonStr(userChatOnlineRecordEntity), e);
        }
    }


    @Override
    public List<UserTurnOnsDto> getuserTurnOnsList() {
        List<UserTurnOnsEntity> userTurnOnsEntities = userTurnOnsDao.selectByParams(new HashMap<>());
        if (CollUtil.isNotEmpty(userTurnOnsEntities)) {
            return userTurnOnsEntities.stream().map(userTurnOnsEntity -> {
                UserTurnOnsDto userTurnOnsDto = new UserTurnOnsDto();
                BeanUtil.copyProperties(userTurnOnsEntity, userTurnOnsDto);
                userTurnOnsDto.setTurnOnsCode(userTurnOnsEntity.getId());
                return userTurnOnsDto;
            }).collect(Collectors.toList());
        }
        return new ArrayList<>();
    }

    @Override
    public void updateUserStatus(String userCode, Integer targetStatus) {
        UserEntity userEntity = userDao.selectByUserCode(userCode);
        if (userEntity == null) {
            return;
        }

        userEntity.setStatus(targetStatus);
        userDao.update(userEntity);
    }


    /**
     * 获取用户会话等级
     */
    @Override
    public Response<Integer> getUserChatLevel(String fromUserCode, String toUserCode) {
        final List<UserMsgSendTotalEntity> userMsgSendTotalEntities = userMsgSendTotalDao.queryByUserCode(fromUserCode, toUserCode);
        if (CollectionUtils.isEmpty(userMsgSendTotalEntities)) {
            return Response.ok(0);
        }

        final Integer sendMessageNum = userMsgSendTotalEntities.get(0).getMsgNum();

        return Response.ok(new UserLevelHelper(sendMessageNum, defaultUserChatLevelConfig).getUserLevel());
    }

    private Map<String, List<UserMsgSendTotalEntity>> getStringListMap(String fromUserCode, String modelUserCode) {
        final List<UserMsgSendTotalEntity> userMsgSendTotalEntities = userMsgSendTotalDao.queryByUserCode(fromUserCode, modelUserCode);
        if (CollectionUtils.isEmpty(userMsgSendTotalEntities)) {
            return null;
        }
        return userMsgSendTotalEntities.parallelStream().collect(Collectors.groupingBy(UserMsgSendTotalEntity::getFromUserCode));
    }

    @Override
    public List<UserInfoDto> listUserInfos(List<String> userCodes) {
        if (org.springframework.util.CollectionUtils.isEmpty(userCodes)) {
            return com.google.api.client.util.Lists.newArrayList();
        }

        Map<String, Object> params = Maps.newConcurrentMap();
        params.put("list", userCodes);
        final List<UserEntity> byUserCodes = userDao.selectUsers(params);
        if (org.springframework.util.CollectionUtils.isEmpty(byUserCodes)) {
            return com.google.api.client.util.Lists.newArrayList();
        }

        return byUserCodes.parallelStream().map(o -> {
            UserInfoDto dto = new UserInfoDto();
            dto.setUserCode(o.getUserCode());
            dto.setNickName(o.getNickName());
            dto.setOnline(o.getOnline());
            return dto;
        }).collect(Collectors.toList());
    }


    @Override
    public Integer updateUserProfile(String userCode, Integer type, String content) {
        final UserProfileEntity userProfile = userProfileDao.queryUsersByUserCodeAndType(userCode, type);
        if (userProfile == null) {
            return 0;
        }
        userProfile.setAboutMe(content);
        return userProfileDao.updateByPrimaryKey(userProfile);
    }

    @NacosValue(value = "${chatter.online.user.list.display.policy.type:3}", autoRefreshed = true)
    private Integer chatterOnlineUserListDisplayPolicyType;

    @NacosValue(value = "${user.online.list.new.cnt:3}", autoRefreshed = true)
    private Integer userOnlineListNewCnt;
    @NacosValue(value = "${user.online.list.old.cnt:2}", autoRefreshed = true)
    private Integer userOnlineListOldCnt;
    @NacosValue(value = "${user.online.list.new.limit.cnt:260}", autoRefreshed = true)
    private Integer getUserOnlineListNewCnt;

    //1.SS 2.S 3.A 4.B
    @NacosValue(value = "${show.chatter.ratings:1,2,3,4}", autoRefreshed = true)
    private String showChatterRatings;

    @Resource
    private CustomersUserDao customersUserDao;

    @Resource
    private FcTrafficHandler fcTrafficHandler;

    @Override
    public List<UserDialogDto> getUsers(String chatterUserCode) {
        List<UserEntity> allUserList;
        List<UserDialogDto> userDialogDtoList = new ArrayList<>();
        // chatter users 新规则
        logger.info("==chatterOnlineUserListData  {}==,policyType:{}", chatterUserCode, chatterOnlineUserListDisplayPolicyType);
        logger.info("==chatterOnlineUserListData  {}==,能有在线列表的主播等级:{}", chatterUserCode, showChatterRatings);
        List<String> showChatterRatingsList = Arrays.asList(showChatterRatings.split(","));
        Integer chatterRating = userDao.getChatterRating(chatterUserCode);
        logger.info("==chatterOnlineUserListData  {}==,获取到当前主播的等级:{}", chatterUserCode, chatterRating);
        chatterRating = chatterRating == null ? 4 : chatterRating;
        if (showChatterRatingsList.contains(chatterRating.toString())) {
            logger.info("==chatterOnlineUserListData  {}==,当前主播等级可以有用户在线列表:{},配置的可展示的数量上限:{}", chatterUserCode, chatterRating, getUserOnlineListNewCnt);
//            List<IssueUsersEntity> issueUsersEntityList = issueUsersDao.getNoneOrganicUsers(getUserOnlineListNewCnt);
            List<IssueUsersDetailEntity> issueUsersListV2 = issueUsersDao.getIssueUsersListV2(getUserOnlineListNewCnt);
            List<IssueUsersDetailEntity> issueUsersDetailEntities = fcTrafficHandler.filterAllApps(chatterUserCode, issueUsersListV2);

//            List<IssueUsersEntity> issueUsersEntityList = filterCustomer(issueUsersDao.getNoneOrganicUsers(getUserOnlineListNewCnt), chatterUserCode);
            logger.info("==chatterOnlineUserListData  {}==,当前主播等级可以有用户在线列表:{},获取到的数据size:{}", chatterUserCode, chatterRating, issueUsersListV2.size());

            for (IssueUsersDetailEntity issueUsersEntity : issueUsersDetailEntities) {
                UserDialogDto userDialogDto = new UserDialogDto();
                userDialogDto.setUserCode(issueUsersEntity.getUserCode());
                userDialogDto.setNickName(issueUsersEntity.getNickName());
                userDialogDto.setGender(issueUsersEntity.getGender());
                userDialogDto.setAvatarUrl(ImagePrefixUtils.getFullImageUrl(issueUsersEntity.getAvatarUrl()));
                userDialogDto.setBirthday(issueUsersEntity.getBirthday());
                userDialogDto.setAge(issueUsersEntity.getAge());
                userDialogDto.setAboutMe(issueUsersEntity.getAboutMe());
                int haveConversation;
                if (chatConversationFlag == 1) {
                    haveConversation = userConversationDao.haveConversation(chatterUserCode, issueUsersEntity.getUserCode());
                } else {
                    haveConversation = userConversationDao.haveChatterConversation(chatterUserCode, issueUsersEntity.getUserCode());
                }
                userDialogDto.setHaveConnection(haveConversation > 0 ? 1 : 0);
                userDialogDto.setConversationCount(0);
                userDialogDtoList.add(userDialogDto);
            }
            logger.info("==chatterOnlineUserListData  {}==,获取完成，size:{}", chatterUserCode, userDialogDtoList.size());
        } else {
            logger.info("==chatterOnlineUserListData  ==,当前主播没有等级,chatterCode:{}", chatterUserCode);
        }

        return userDialogDtoList;
    }


    private List<UserEntity> randomShowSome(List<UserEntity> newUserList, List<UserEntity> oldUserList) {
        int allUserCnt = userOnlineListNewCnt + userOnlineListOldCnt;
        List<UserEntity> userEntityList = new ArrayList<>();
        if (!newUserList.isEmpty()) {
            Collections.shuffle(newUserList);
            for (UserEntity userEntity : newUserList) {
                int breakCount = 2;
                if (!oldUserList.isEmpty() && userEntityList.size() < userOnlineListNewCnt) {
                    userEntityList.add(userEntity);
                    breakCount = breakCount - 1;
                }
                if (oldUserList.isEmpty() && userEntityList.size() <= allUserCnt) {
                    userEntityList.add(userEntity);
                    breakCount = breakCount - 1;
                }
                if (breakCount == 2) {
                    break;
                }
            }
        }
        if (!oldUserList.isEmpty()) {
            Collections.shuffle(oldUserList);
            List<UserEntity> oldUserEntityList = new ArrayList<>();
            userOnlineListOldCnt = allUserCnt - userEntityList.size();
            for (UserEntity userEntity : oldUserList) {
                int breakCount = 2;
                if (!userEntityList.isEmpty() && oldUserEntityList.size() < userOnlineListOldCnt) {
                    oldUserEntityList.add(userEntity);
                    breakCount = breakCount - 1;
                }
                if (userEntityList.isEmpty() && oldUserEntityList.size() <= allUserCnt) {
                    oldUserEntityList.add(userEntity);
                    breakCount = breakCount - 1;
                }
                if (breakCount == 2) {
                    break;
                }
            }
            userEntityList.addAll(oldUserEntityList);
        }
        return userEntityList;
    }

    private List<UserEntity> showAll(String chatterUserCode, List<UserEntity> newUserList, List<UserEntity> oldUserList) {
        return joinLists(newUserList, oldUserList);
    }

    private List<UserEntity> ensureUserSeeDifferent(String chatterUserCode, List<UserEntity> newUserList, List<UserEntity> oldUserList) {
        List<UserEntity> userEntities = new ArrayList<>();
        return userEntities;
    }

    /**
     * 两个list交错
     *
     * @param list1
     * @param list2
     * @return
     */
    private List<UserEntity> joinLists(List<UserEntity> list1, List<UserEntity> list2) {
        // 构建结果list，长度为两个入参list长度之和
        List<UserEntity> list = new ArrayList<UserEntity>(list1.size() + list2.size());
        // 若list1长度大于list2
        if (list1.size() > list2.size()) {
            // 以list2的长度为限制，开始循环
            for (int i = 0; i < list2.size(); i++) {
                list.add(list1.get(i));
                list.add(list2.get(i));
            }
            // 将list1 中多于list2长度的元素，放入list中
            list.addAll(list1.subList(list2.size(), list1.size()));
        } else if (list1.size() < list2.size()) { // 若list2 的长度大于list1
            // 以list1的长度为限制，开始循环
            for (int i = 0; i < list1.size(); i++) {
                list.add(list1.get(i));
                list.add(list2.get(i));
            }
            // 将list2 中多于list1长度的元素，放入list中
            list.addAll(list2.subList(list1.size(), list2.size()));
        } else { // list1 长度与list2 长度相等
            for (int i = 0; i < list1.size(); i++) {
                list.add(list1.get(i));
                list.add(list2.get(i));
            }
        }
        return list;
    }

    @Override
    public List<ModelDto> getModels(String chatterUserCode, String userCode) {
        logger.info("---------- getModels chatterUserCode:{},用户:{}", chatterUserCode, userCode);
        List<String> modelCodes = userChatterMappingDao.selectAll(chatterUserCode);
        logger.info("---------- getModels chatter【{}】下面的model有{}", chatterUserCode, modelCodes);
        List<ModelDto> modelDos = new ArrayList<>();
        if (modelCodes.isEmpty()) {
            logger.info("---------- getModels 为空 chatter【{}】下面的model有{}", chatterUserCode, modelCodes);
            return modelDos;
        }

        Map<String, Object> params = Maps.newConcurrentMap();
        params.put("list", modelCodes);
        List<UserEntity> userEntityList = userDao.selectUsers(params);
        logger.info("---------- getModels 查找到model的user表信息 chatter【{}】下面的model有{}，userEntityList:{}", chatterUserCode, modelCodes, userEntityList.size());

        CustomersUserEntity customer = customersUserDao.getCustomer(userCode);
        logger.info("---------- getModels 当前用户的自然人信息 customerCode:{}", customer.getCustomerCode());
        List<UserWlmEntity> userWlmEntities = userWlmDao.listCustomerLbModel(customer.getCustomerCode(), modelCodes);
        List<String> modelsHasConnectionWithThisCustomer = userWlmEntities.parallelStream().map(UserWlmEntity::getUserCodeWlm).distinct().collect(Collectors.toList());
        logger.info("---------- getModels 找到当前chatter下面的所有model和自然人的建联关系 customerCode:{} 建联过的model:{}", customer.getCustomerCode(), modelsHasConnectionWithThisCustomer);

        Map<String, List<String>> userCodeAndItsConnectedModels = userWlmEntities.stream()
                .collect(Collectors.groupingBy(UserWlmEntity::getUserCode,
                        Collectors.mapping(UserWlmEntity::getUserCodeWlm,
                                Collectors.toList())));

        logger.info("==---------- getModels ==,userCodeAndItsConnectedModels:{}", userCodeAndItsConnectedModels);

        Map<String, List<String>> modelAndItsConnectedUsers = userWlmEntities.stream()
                .collect(Collectors.groupingBy(UserWlmEntity::getUserCodeWlm,
                        Collectors.mapping(UserWlmEntity::getUserCode,
                                Collectors.toList())));
        logger.info("==---------- getModels ==,modelAndItsConnectedUsers:{}", modelAndItsConnectedUsers);

        for (UserEntity userEntity : userEntityList) {
            String modelCode = userEntity.getUserCode();
            ModelDto modelDto = new ModelDto();
            modelDto.setUserCode(userEntity.getUserCode());
            String token = userAccessRongcloudDao.getRongCloudToken(userEntity.getUserCode());
            if (StringUtils.isNotEmpty(token)) {
                modelDto.setToken(token);
            }
            modelDto.setNickName(userEntity.getNickName());
            modelDto.setAvatarUrl(ImagePrefixUtils.getFullImageUrl(userEntity.getAvatarUrl()));
            modelDto.setBirthday(userEntity.getBirthday());
            modelDto.setAge(ageCalculation(userEntity.getBirthday()));
            modelDto.setHaveBlack(0);
            int blackCount = userWlmDao.getBlackCount(userCode, userEntity.getUserCode());

            //如果当前model被禁用，或者被用户拉黑我们不可点击
            if (userEntity.getStatus() == 1 || blackCount > 0) {
                logger.info("==---------- getModels 当前model被禁用或者被用户拉黑 ==,status:{},blackCount:{}", userEntity.getStatus(), blackCount);
                modelDto.setHaveBlack(1);
                modelDto.setHaveBlackTips(userEntity.getStatus() == 1 ? "This model has been disabled" : "Model is already connected to this user");
            } else {
                //如果当前model建联过
                if (modelAndItsConnectedUsers.containsKey(modelCode)) {
                    logger.info("==---------- getModels model有建联 ==,modelCode:{}", userEntity.getUserCode());
                    //当前model和当前用户建联
                    boolean currentModelHasConnectWithCurrentUser = userCodeAndItsConnectedModels.containsKey(userCode) && userCodeAndItsConnectedModels.get(userCode).contains(modelCode);
                    if (!currentModelHasConnectWithCurrentUser) {
                        logger.info("==---------- getModels model有建联 但是不是和当前用户建联 ==,modelCode:{}", userEntity.getUserCode());
                        modelDto.setHaveBlack(1);
                        modelDto.setHaveBlackTips("This model has already had a chat with this user");
                    } else {
                        logger.info("==---------- getModels model和当前用户建联了 ==,modelCode:{}", userEntity.getUserCode());
                    }
                }

            }
            modelDos.add(modelDto);
        }
        return modelDos;
    }

    public static void main(String[] args) {
        List<UserWlmEntity> userWlmEntities = new ArrayList<>();
        userWlmEntities.add(new UserWlmEntity().setUserCode("aa").setUserCodeWlm("1"));
        userWlmEntities.add(new UserWlmEntity().setUserCode("aa").setUserCodeWlm("2"));
        userWlmEntities.add(new UserWlmEntity().setUserCode("bb").setUserCodeWlm("3"));
        userWlmEntities.add(new UserWlmEntity().setUserCode("bb").setUserCodeWlm("4"));
        Map<String, List<String>> map = userWlmEntities.stream()
                .collect(Collectors.groupingBy(UserWlmEntity::getUserCode,
                        Collectors.mapping(UserWlmEntity::getUserCodeWlm,
                                Collectors.toList())));
        System.err.println(map);
    }


    private List<String> modelsHasConnectionWithThisCustomer(String customerCode, List<String> modelCodes) {
        List<UserWlmEntity> userWlmEntities = userWlmDao.listCustomerLbModel(customerCode, modelCodes);
        return userWlmEntities.parallelStream().map(UserWlmEntity::getUserCodeWlm).distinct().collect(Collectors.toList());
    }

    @Override
    public Boolean haveConversationByModel(String chatterUserCode, String modelUserCode, String userCode) {
        Boolean result = false;
        UserConversationEntity userConversationEntity = userConversationDao.conversationByModel(chatterUserCode, modelUserCode, userCode);
        if (userConversationEntity != null) {
            long timeRange = 5 * 60 * 1000;
            long startRange = System.currentTimeMillis() - timeRange;
            long creatTime = userConversationEntity.getGmtCreate().getTime();
            if (creatTime >= startRange && creatTime <= System.currentTimeMillis()) {
                return true;
            }
        } else {
            return true;
        }
        return result;
    }

    @Override
    public Integer getChatterRating(String chatterUserCode) {
        return userDao.getChatterRating(chatterUserCode);
    }

    @Override
    public Integer checkLogout(String userCode) {
        Integer result = 0;
        result = userLogoutDao.getRecordByUserCode(userCode);
        if (result > 0) {
            userLogoutDao.deleteByUserCode(userCode);
        }
        return result;
    }

    @Override
    public void addLogoutRecord(String userCode) {
        UserLogoutEntity userLogoutEntity = new UserLogoutEntity();
        userLogoutEntity.setUserCode(userCode);
        userLogoutDao.insert(userLogoutEntity);
    }

    @Override
    public Response<UserGpsDto> getGpsInfo(String userCode) {
        UserBehaviorGpsEntity userBehaviorGpsEntity = userBehaviorGpsDao.getLastGps(userCode);
        return Response.ok(UserBehaviorGpsEntity.toDto(userBehaviorGpsEntity));
    }

    @Override
    public Response<UserTagDto> getUserTagInfo(String userCode) {
        if (StringUtils.isEmpty(userCode)) {
            return Response.ok();
        }
        final List<UserTagDBO> userTagDBOS = userTagDao.listUserTag(userCode);
        if (CollectionUtils.isEmpty(userTagDBOS)) {
            return Response.ok();
        }

        final List<SelectVal> userTagList = userTagDBOS.stream().map(o -> SelectVal.builder().type(o.getTagType()).code(Long.valueOf(String.valueOf(o.getTagCode()))).value(o.getTagName()).build()).collect(Collectors.toList());

        final Map<Integer, List<SelectVal>> userTagMap = userTagList.stream().collect(Collectors.groupingBy(SelectVal::getType));

        final UserTagDto userTagDto = UserTagDto.builder().build();
        if (userTagMap.containsKey(Integer.valueOf(ConstantType.I_WANT))) {
            final List<SelectVal> iWantList = userTagMap.get(Integer.valueOf(ConstantType.I_WANT));
            if (CollectionUtils.isNotEmpty(iWantList)) {
                userTagDto.setUserWant(iWantList.get(0));
            }
        }

        if (userTagMap.containsKey(Integer.valueOf(ConstantType.YOU_ACCEPT))) {
            userTagDto.setYouAccept(userTagMap.get(Integer.valueOf(ConstantType.YOU_ACCEPT)));
        }

        if (userTagMap.containsKey(Integer.valueOf(ConstantType.BODY_SHAPE))) {
            userTagDto.setBodyShape(userTagMap.get(Integer.valueOf(ConstantType.BODY_SHAPE)));
        }

        return Response.ok(userTagDto);
    }

    @Override
    public Integer checkOnline(String userCode, String dates) {
        if (StringUtils.isNotEmpty(dates) && dates.contains("-")) {
            dates = dates.replace("-", "");
        }
        return userOnlineLogDao.checkOnline(userCode, dates);
    }

    @Override
    public int updateChatterRating(String userCode, Integer chatterRating) {
        return userDao.updateChatterRating(userCode, chatterRating);
    }

    @Override
    public boolean canConnect(String userCode) {
        boolean result = false;
        UserEntity userEntity = userDao.selectByUserCode(userCode);
        Date begin = userEntity.getRegisterDate() != null ? userEntity.getRegisterDate() : userEntity.getGmtCreate();
        Date end = new Date();
        long between = (end.getTime() - begin.getTime()) / 1000;
        long distanceMinute = between / 60;
        //注册时间距离现在多少分钟
        if (distanceMinute <= 5) {
            Map<String, Object> params = Maps.newHashMap();
            params.put("userCode", userCode);
            params.put("deleted", 0);
            int conversationCount = userConversationDao.queryTotal(params);
            if (conversationCount >= 2) {
                return result;
            }
        } else if (distanceMinute <= 15) {
            Map<String, Object> params = Maps.newHashMap();
            params.put("userCode", userCode);
            params.put("deleted", 0);
            int conversationCount = userConversationDao.queryTotal(params);
            if (conversationCount >= 6) {
                return result;
            }
        }

        Map<String, Object> params = Maps.newHashMap();
        params.put("userCode", userCode);
        params.put("deleted", 0);
        int count = issueUsersDao.queryTotal(params);
        if (count > 0) {
            issueUsersDao.deleteByUserCode(userCode);
            result = true;
        }
        return result;
    }

    private Integer ageCalculation(Date birthday) {
        Integer age = null;
        if (Objects.nonNull(birthday)) {
            try {
                age = TimeUtils.getAge(birthday);
            } catch (Exception e) {
                logger.error("Age calculation error, birthday:{}", birthday);
            }
        }
        return age;
    }

}
